<template>
  <div class="views" id="views">
    <div id="container" class="container"></div>
  </div>
</template>

<script>
import { App } from '@/assets/App/App'
import * as THREE from 'three'
import { GUI } from 'three/examples/jsm/libs/dat.gui.module.js'

const app = new App()
export default {
  data () {
    return {
      params: {
        methods: {
          animation: false, // 循环调用渲染
          renderer: true, // 应用渲染器
          light: true, // 在场景中加入全景光
          statement: true // 在控制台打印声明，与本案例无关，可忽略。
        },
        events: {
          windowResize: true // 监听窗口尺寸变化，并改变渲染页面尺寸
        },
        params: {
          container: null, // 渲染结果输出dom页面
          renderer: [
            'WebGLRenderer'
          ],
          rendererParams: {
            antialias: true // 抗锯齿，可忽略。
          }
        }
      }
    }
  },
  mounted () {
    this.params.params.container = document.getElementById('container') // 获取渲染结果输出dom页面
    /**
     * 初始化场景
     */
    app.init(this.params, (scene, camera, renderer) => {
      camera.position.set(-5, 3, 10)
      camera.lookAt(new THREE.Vector3(0, 2, 0))

      scene.background = new THREE.Color(0xe0e0e0)
      scene.fog = new THREE.Fog(0xe0e0e0, 20, 100)

      renderer.setPixelRatio(window.devicePixelRatio)
      renderer.outputEncoding = THREE.sRGBEncoding

      this.clock = new THREE.Clock()
    })
    /**
     * 导入模型
     */
    app.addModel({
      url: 'static/model/glb/RobotExpressive.glb', // 模型地址
      type: 'glb', // 模型格式
      name: 'robot',
      animations: true
    }, (obj, animations, mixer, actions) => {
      this.model = obj
      this.animations = animations
      this.mixer = mixer
      this.actions = actions

      // 创建gui
      this.createGUI(obj, animations, mixer, actions)

      // 循环渲染
      app.animate(() => {
        var dt = this.clock.getDelta()
        if (mixer && this.enabled) mixer.update(dt)
      })
    })
  },
  methods: {
    createGUI (model, animations, mixer, actions) {
      const that = this

      var api = { state: 'Walking' }
      var states = ['Idle', 'Walking', 'Running', 'Dance', 'Death', 'Sitting', 'Standing']
      var emotes = ['Jump', 'Yes', 'No', 'Wave', 'Punch', 'ThumbsUp']

      this.actions = {} // 重写actions

      for (var i = 0; i < animations.length; i++) {
        var clip = animations[i]
        var action = mixer.clipAction(clip)
        this.actions[clip.name] = action

        if (emotes.indexOf(clip.name) >= 0 || states.indexOf(clip.name) >= 4) {
          action.clampWhenFinished = true
          action.loop = THREE.LoopOnce
        }
      }

      const gui = new GUI()
      this.gui = gui // 将gui加到this

      // enabled

      var enabledFolder = gui.addFolder('Enabled')
      enabledFolder.add({ enabled: false }, 'enabled').onChange((value) => {
        that.enabled = value
      })
      enabledFolder.open()

      // states

      var statesFolder = gui.addFolder('States')

      var clipCtrl = statesFolder.add(api, 'state').options(states)

      clipCtrl.onChange(function () {
        that.fadeToAction(api.state, 0.5)
      })

      statesFolder.open()

      // emotes

      var emoteFolder = gui.addFolder('Emotes')

      function createEmoteCallback (name) {
        api[name] = function () {
          that.fadeToAction(name, 0.2)
          mixer.addEventListener('finished', restoreState)
        }

        emoteFolder.add(api, name)
      }

      function restoreState () {
        mixer.removeEventListener('finished', restoreState)
        that.fadeToAction(api.state, 0.2)
      }

      for (var i = 0; i < emotes.length; i++) {
        createEmoteCallback(emotes[i])
      }

      emoteFolder.open()

      // expressions

      var face = model.getObjectByName('Head_2')

      var expressions = Object.keys(face.morphTargetDictionary)
      var expressionFolder = gui.addFolder('Expressions')

      for (var i = 0; i < expressions.length; i++) {
        expressionFolder.add(face.morphTargetInfluences, i, 0, 1, 0.01).name(expressions[i])
      }

      expressionFolder.open()

      this.activeAction = actions['Walking']
      this.activeAction.play()
    },
    fadeToAction (name, duration) {
      var previousAction = this.activeAction
      this.activeAction = this.actions[name]

      if (previousAction !== this.activeAction) {
        previousAction.fadeOut(duration)
      }

      this.activeAction
        .reset()
        .setEffectiveTimeScale(1)
        .setEffectiveWeight(1)
        .fadeIn(duration)
        .play()
    }
  },
  beforeDestroy () {
    this.gui.destroy()
  }
}
</script>

<style scoped>
.views {
  height: 100%;
  width: 100%;
}

.container {
  height: 100%;
  width: 100%;
}
</style>
